Craft Your Own SSH Client in Python with CustomTkinter

Python’s versatility extends to network automation and remote server management. This guide delves into building a custom SSH client using Python, leveraging the capabilities of CustomTkinter and Fabric libraries to create a user-friendly interface.

  • Save

Why Craft Your Own SSH Client?

Building your own SSH client empowers you to tailor functionality to your specific workflow. Whether you juggle multiple servers or automate repetitive tasks, a custom client streamlines your efforts.

Leveraging CustomTkinter’s Power

CustomTkinter builds upon the standard Tkinter library, offering a modern and customizable aesthetic for your GUI applications. It facilitates creating sleek interfaces while retaining Tkinter’s simplicity.

Effortlessly Establish SSH Connections

The Fabric library simplifies establishing SSH connections in Python. With a few lines of code, you can connect to a remote server, execute commands, and manage outputs.

Unveiling the Code

We begin by importing essential modules and defining color schemes for the UI. Next, we create a JSON object storing common commands for easy access.

Credentials are securely retrieved from a configuration file, a best practice for handling sensitive information. The SSH client configuration specifies preferred algorithms for key exchange, ciphers, MACs, and compression.

The SSHClientApp class inherits from customtkinter.CTk, crafting the main application window with distinct sections for the top bar, side menu, and main body. The side menu features a list box populated with commands from our JSON object, allowing users to swiftly select and execute them.

The main body incorporates an output text box displaying command results, an entry field for typing commands, and a reconnect button for establishing or re-establishing the SSH connection.

Functionality at Your Command

This custom SSH client empowers you to reconnect to the server, execute commands (either selected or typed), and view results in real-time.

Embrace the Power of Customization

Building your own SSH client in Python is not only educational but also highly practical. CustomTkinter and Fabric empower you to create a powerful tool tailored to your specific needs.

Ready to Ascend Your Python Mastery?

Stay tuned for more in-depth explorations of network automation and GUI development in Python. If you found this article valuable, consider sharing it with your network!

import tkinter as tk
import json
from fabric import Connection, Config
from paramiko import AutoAddPolicy, SSHClient
import customtkinter
from CTkListbox import CTkListbox  # Importar CTkListbox desde el módulo separado

# Replace with your actual color configuration or import from your config file
COLOR_top_bar = '#333'
COLOR_CUERPO_PRINCIPAL = '#000000'
COLOR_MENU_CURSOR_ENCIMA = '#555'
COLOR_MENU_LATERAL = '#222'

# Sample JSON configuration for commands
commands = {
    "Comandos": [
        "ping -c 4 8.8.8.8",
        "iwlist ath0 frequency",
        "iwlist ath0 channel",
        "iwlist ath0 bitrate",
        "iwlist ath0 rate",
        "iwlist ath0 auth",
        "iwconfig",
        "iwlist ath0 genie",
        "iwlist ath0 txpower",
        "reboot",
        "cat /tmp/system.cfg | grep http",
        "iwlist ath0 scan",
        "ifconfig",
        "ls /etc/",
        "ls",
        "passwd",
        "discover",
        "cp /usr/etc/system.cfg /tmp/system.cfg;",
        "save",
        "reboot"
    ]
}

# Read configuration from the config.json file
with open('./util/config.json', 'r') as f:
    config = json.load(f)

username = config['username']
password = config['password']
default_ip = config['default_ip']

# Configure SSH algorithms
preferred_kex = [
    'diffie-hellman-group1-sha1',
    'diffie-hellman-group14-sha1',
    'diffie-hellman-group-exchange-sha1'
]
preferred_ciphers = [
    'aes128-ctr', 'aes192-ctr', 'aes256-ctr',
    'aes128-cbc', '3des-cbc', 'aes192-cbc', 'aes256-cbc'
]
preferred_macs = [
    'hmac-sha1', 'hmac-md5'
]
preferred_compression = ['none']

client = SSHClient()
client.set_missing_host_key_policy(AutoAddPolicy())

class SSHClientApp(customtkinter.CTk):
    def __init__(self):
        super().__init__()
        self.title("SSH Client")
        self.geometry("1024x600")

        self.create_widgets()
        self.conn = None
        self.connect_ssh()

    def create_widgets(self):
        self.create_top_bar()
        self.create_side_menu()
        self.create_main_body()

    def create_top_bar(self):
        self.top_bar = customtkinter.CTkFrame(self, fg_color=COLOR_top_bar, height=50)
        self.top_bar.pack(side=tk.TOP, fill='both')

        self.menu_button = customtkinter.CTkButton(self.top_bar, text="☰", command=self.toggle_side_menu, fg_color=COLOR_top_bar, hover_color=COLOR_MENU_CURSOR_ENCIMA)
        self.menu_button.pack(side=tk.LEFT, padx=10)

        self.title_label = customtkinter.CTkLabel(self.top_bar, text="Consola SSH", text_color="white", fg_color=COLOR_top_bar)
        self.title_label.pack(side=tk.LEFT, padx=10)

        self.close_button = customtkinter.CTkButton(self.top_bar, text="Cerrar", command=self.quit, fg_color=COLOR_top_bar, hover_color=COLOR_MENU_CURSOR_ENCIMA)
        self.close_button.pack(side=tk.RIGHT, padx=10)

    def create_side_menu(self):
        self.side_menu = customtkinter.CTkFrame(self, fg_color=COLOR_MENU_LATERAL, width=150)
        self.side_menu.pack(side=tk.LEFT, fill='both', expand=False)

        self.profile_label = customtkinter.CTkLabel(self.side_menu, text="Comandos más usados", fg_color=COLOR_MENU_LATERAL)
        self.profile_label.pack(side=tk.TOP, pady=10)

        self.command_listbox = CTkListbox(self.side_menu, fg_color=COLOR_MENU_LATERAL, text_color="white")
        for command in commands["Comandos"]:
            self.command_listbox.insert(tk.END, command)
        self.command_listbox.pack(side=tk.TOP, fill='both', expand=True)
        self.command_listbox.bind('<<ListboxSelect>>', self.on_command_select)

    def create_main_body(self):
        self.main_body = customtkinter.CTkFrame(self, fg_color=COLOR_CUERPO_PRINCIPAL)
        self.main_body.pack(side=tk.RIGHT, fill='both', expand=True)

        self.output_text = customtkinter.CTkTextbox(self.main_body, wrap='word', text_color="white", fg_color=COLOR_CUERPO_PRINCIPAL)
        self.output_text.pack(padx=15, pady=15, fill='both', expand=True)

        self.command_entry = customtkinter.CTkEntry(self.main_body, placeholder_text="Command", text_color="white", fg_color="#2A3138")
        self.command_entry.pack(side=tk.LEFT, padx=15, pady=5, fill='x', expand=True)
        self.command_entry.bind('<Return>', self.execute_command)

        self.connect_button = customtkinter.CTkButton(self.main_body, text="Reconectar", command=self.connect_ssh, fg_color="#2F88C5", hover_color="#1E62D0")
        self.connect_button.pack(side=tk.LEFT, padx=5, pady=5)

    def toggle_side_menu(self):
        if self.side_menu.winfo_ismapped():
            self.side_menu.pack_forget()
        else:
            self.side_menu.pack(side=tk.LEFT, fill='both', expand=False)

    def connect_ssh(self):
        try:
            configure = Config(overrides={'sudo': {'password': password}})
            self.conn = Connection(default_ip, user=username, config=configure, connect_kwargs={"password": password})
            self.append_to_output(f"Conectado a {default_ip} como {username}\n")
        except Exception as e:
            self.append_to_output(f"Error al conectar: {str(e)}\n")

    def execute_command(self, event=None):
        command = self.command_entry.get()
        self.command_entry.delete(0, tk.END)
        self.append_to_output(f"Ingresando comando: {command}\n")

        if self.conn:
            try:
                result = self.conn.run(command)
                output_text = result.stdout
                self.append_to_output(output_text)
            except Exception as e:
                self.append_to_output(f"Error al ejecutar comando: {str(e)}\n")

    def on_command_select(self, event):
        selected_command = self.command_listbox.get(self.command_listbox.curselection())
        self.command_entry.delete(0, tk.END)
        self.command_entry.insert(0, selected_command)

    def append_to_output(self, text):
        self.output_text.insert(tk.END, text)
        self.output_text.see(tk.END)

if __name__ == "__main__":
    app = SSHClientApp()
    app.mainloop()

Explanation of the Python code for the SSH Client with CustomTkinter

This code builds a graphical user interface (GUI) application for connecting to a remote server using SSH and executing commands. Here’s a breakdown of the key parts:

1. Imports:

  • The code starts by importing necessary libraries:
    • tkinter: This is the core Tkinter library for building GUIs in Python.
    • json: Used to handle the JSON configuration file containing common commands.
    • fabric: Simplifies establishing SSH connections and executing commands.
    • paramiko: Low-level library for interacting with the SSH protocol.
    • customtkinter: Provides a more modern and customizable look for the Tkinter interface.
    • CTkListbox: Imports the custom list box component from customtkinter.

2. Configuration:

  • Color variables define the color scheme for different UI elements (COLOR_top_bar, etc.).
  • A sample JSON object (commands) stores a list of commonly used commands for quick access.
  • The code reads username, password, and default IP address from a configuration file (config.json).
  • SSH connection preferences are set for key exchange algorithms, ciphers, MACs, and compression (preferred_kex, etc.).

3. SSH Client Setup:

  • An SSHClient object (client) is created from the paramiko library.
  • It sets a policy to automatically accept new SSH host keys (set_missing_host_key_policy).

4. Main Application Class (SSHClientApp):

  • This class inherits from customtkinter.CTk and defines the main application window.
    • __init__: Initializes the window title, geometry (size), creates widgets, establishes an initial connection, and stores the connection object.
    • create_widgets: Creates the different UI elements of the application:
      • create_top_bar: Defines the top bar with a menu button, application title, and close button.
      • create_side_menu: Creates a left-side menu containing a label and a list box populated with commands from the JSON configuration.
      • create_main_body: Defines the main body area with an output text box for displaying results, a command entry field for typing commands, and a reconnect button.
    • Other methods handle specific functionalities:
      • toggle_side_menu: Shows or hides the side menu when the menu button is clicked.
      • connect_ssh: Attempts to connect to the server using the provided credentials and configuration.
        • In case of a successful connection, it displays a message and stores the connection object.
        • If connection fails, it displays an error message.
      • execute_command: Handles running commands based on user input or selected commands.
        • It retrieves the command from the entry field, clears the field, displays “Ingresando comando” (Entering command), and sends the command to the server if connected.
        • The output from the server is displayed in the text box. Any errors are also captured and displayed.
      • on_command_select: Populates the command entry field with the selected command from the list box.
      • append_to_output: Appends text to the output text box and ensures it scrolls to the end for new content.

5. Running the Application:

  • The if __name__ == "__main__": block ensures the code within this block only executes when the script is run directly (not imported as a module).
  • It creates an instance of the SSHClientApp class and starts the main event loop (mainloop) to keep the GUI application running and respond to user interactions.

This code provides a basic framework for an SSH client with a user-friendly interface. You can customize it further by adding features like saving frequently used commands, handling different server connections, or implementing more advanced output formatting.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Share via
Copy link